package valuecomusa.fijibus.eticket.shorthaul;


import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.media.MediaPlayer;
//import android.nfc.NfcAdapter;
import android.os.*;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.*;
import valuecomusa.fijibus.eticket.*;
import valuecomusa.fijibus.eticket.db.shorthaul.BusinessDBHandler;
import valuecomusa.fijibus.eticket.db.shorthaul.GpsDBHandler;
import valuecomusa.fijibus.eticket.dialog.refund;
import valuecomusa.fijibus.eticket.dto.GpsCurrentLocationValue;
import valuecomusa.fijibus.eticket.dto.StagesOfRouteValue;
import valuecomusa.fijibus.eticket.ws.MemberValue;
import valuecomusa.fijibus.eticket.ws.PassengerTypeValue;
import valuecomusa.fijibus.eticket.ws.TransactionValue;
import valuecomusa.fijibus.eticket.ws.VoucherValue;

import java.util.*;

public class CheckInV2Cash extends SunbeamActivity
{
	private static int counter = 1;
    private String TAG = "CheckInV2-Cash";
    private StagesOfRouteValue currentLocation;

    private int[] passengerCount = new int[5]; //adult, child, senior, disabled, student
    private double totalFare;
    private double xStageFare;
    private int stageCount;
    //--
    //private double oneStageFare;
    //--
    private TextView totalFareTextView;

    private BusinessDBHandler db;
    private GpsDBHandler gpsDb;

    private List<PassengerTypeValue> passengerTypeList;
    //--
    private ProgressDialog progress;
	//--
//	private NfcAdapter nfcAdapter;
//	private PendingIntent mPendingIntent;

	public CheckInV2Cash()
	{
		TAG = TAG + "." + counter++;
		if(counter > 1000000)
			counter = 1;
	}

    private double GetPassengerTypeDiscount(String type)
    {
		try
		{
			for (PassengerTypeValue xx : this.passengerTypeList)
			{
				if (xx.Type.toLowerCase().equals(type.toLowerCase()))
					return xx.Discount / 100;
			}
		}
		catch (Exception ex)
		{
			Log.e(TAG, String.format("[GetPassengerTypeDiscount] type: %s, %s", type, ex.getMessage()));
		}
        return 0;
    }

    private void Initialize()
    {
	//--
        currentLocation = null;
        Arrays.fill(passengerCount, 0); //adult, child, senior, disabled, student
        totalFare = 0;
        xStageFare = 0;
        stageCount = db.getStageCountOfRoute(WorkingSession.getInstance().journalRoute.ISN);
        passengerTypeList = null;
        //--
        totalFareTextView = (TextView) findViewById(R.id.tvFare);
        //--
        progress = new ProgressDialog(this);
        progress.setMessage("Waiting...");
        progress.setCancelable(false);
        //--
        HandlerThread uiThread = new HandlerThread("UIThreadHandler");//to prepare a looper
        uiThread.start();
        uiThreadHandler = new UIThreadHandler(uiThread.getLooper()); //to process UI such as AlertDialog,...
    }

    private void fillMemberInfo()
    {
        TextView x = (TextView) findViewById(R.id.tvCustID);
        x.setText(WorkingSession.getInstance().currentPassenger.UserName + " ("
                + WorkingSession.getInstance().currentPassenger.getFullName() + ")");

        totalFareTextView.setText(String.valueOf(WorkingSession.getInstance().RoundMoney(totalFare)));

    }

    private void ShowStagesByPassengerType(int passengerType, int stageCount)
    {
        for(int i=3; i> stageCount && i > 0; i--)
        {
            int id = -1;
            switch (passengerType)
            {
                case PassengerTypeValue.ADULT_PASSENGER:
                    id = Utilities.getResId("stage_adult_" + i, CheckInV2Cash.this, R.id.class);
                    if(id > -1)
                        findViewById(id).setVisibility(View.GONE);
                    break;
                case PassengerTypeValue.CHILD_PASSENGER:
                    id = Utilities.getResId("stage_child_" + i, CheckInV2Cash.this, R.id.class);
                    if(id > -1)
                        findViewById(id).setVisibility(View.GONE);
                    break;
                case PassengerTypeValue.SENIOR_PASSENGER:
                    id = Utilities.getResId("stage_senior_" + i, CheckInV2Cash.this, R.id.class);
                    if(id > -1)
                        findViewById(id).setVisibility(View.GONE);
                    break;
                case PassengerTypeValue.DISABLED_PASSENGER:
                    id = Utilities.getResId("stage_disabled_" + i, CheckInV2Cash.this, R.id.class);
                    if(id > -1)
                        findViewById(id).setVisibility(View.GONE);
                    break;
                case PassengerTypeValue.STUDENT_PASSENGER:
                    id = Utilities.getResId("stage_student_" + i, CheckInV2Cash.this, R.id.class);
                    if(id > -1)
                        findViewById(id).setVisibility(View.GONE);
                    break;
            }
        }
    }

    private void ShowStageButton()
    {
        ShowStagesByPassengerType(PassengerTypeValue.ADULT_PASSENGER, stageCount);
        ShowStagesByPassengerType(PassengerTypeValue.CHILD_PASSENGER, stageCount);
        ShowStagesByPassengerType(PassengerTypeValue.SENIOR_PASSENGER, stageCount);
        ShowStagesByPassengerType(PassengerTypeValue.DISABLED_PASSENGER, stageCount);
        ShowStagesByPassengerType(PassengerTypeValue.STUDENT_PASSENGER, stageCount);
    }

    private void ChangeTitle()
    {
        TextView title = (TextView) findViewById(R.id.title_text);
        title.setText(getString(R.string.title_activity_check_in_no_card));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate...");
        // --
        setContentView(R.layout.check_in_v2_cash);

        WorkingSession.getInstance().currentActivity = CheckInV2Cash.this;

        //--
        db = new BusinessDBHandler(CheckInV2Cash.this);
        gpsDb = new GpsDBHandler(CheckInV2Cash.this);
        // --
        super.doCommon();
        Initialize();
        //--
        //this.oneStageFare = db.getStageFare(WorkingSession.getInstance().setupJournal.RouteISN, 1);
        //--
        RegisterPayByEvent();
        RegisterPassengerStageClickEvent();
        ShowStageButton();
        ChangeTitle();
        //--
        passengerTypeList = db.getPassengerType();
        if (passengerTypeList == null || passengerTypeList.size() == 0)
        {
            Log.d(TAG, "Could not get Passenger Type discount");
            WorkingSession.getInstance().ShowToast(this,
                    "Could not get Passenger Type's discount",
                    Toast.LENGTH_LONG);
            return;
        }
        //--
        List<StagesOfRouteValue> stageList = db.getStagesOfRoute(WorkingSession.getInstance().journalRoute.ISN);
        ArrayAdapter<StagesOfRouteValue> stages = new ArrayAdapter<StagesOfRouteValue>(this,
                android.R.layout.simple_dropdown_item_1line, stageList);
        //---
        Spinner xx = (Spinner) findViewById(R.id.checkin_current_location);
        xx.setAdapter(stages);
        xx.setOnItemSelectedListener(currentLocationItemClick);
        //---
        Button xxClick = (Button) findViewById(R.id.checkin_current_location_click);
        xxClick.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                Spinner xx = (Spinner) findViewById(R.id.checkin_current_location);
                xx.performClick();
            }
        });

        //---
        fillMemberInfo();

        //---
        if (xStageFare < 0)
        {
            WorkingSession.getInstance().ShowToast(this, "Could not get Fare", Toast.LENGTH_LONG);
        }
        //--
        Log.d(TAG,"Detect current location...");
        //--
        GpsCurrentLocationValue currentGpsLocation = gpsDb.getCurrentLocation(
                WorkingSession.getInstance().setupJournal.ISN);
        if (currentGpsLocation != null)
        {
            Log.d(TAG, String.format("Current location: %d", currentGpsLocation.ClosestStage));
            int idx = -1;
            for (int i = 0; i < stageList.size(); i++)
            {
                Log.d(TAG, String.format("Stage: %d", stageList.get(i).StageISN));
                if (stageList.get(i).StageISN == currentGpsLocation.ClosestStage &&
                        stageList.get(i).BusStationISN == currentGpsLocation.ClosestBusStation)
                {
                    idx = i;
                    break;
                }
            }
            if (idx != -1)
                xx.setSelection(idx);
        }
        //-- play bula voice
        //Utilities.PlayMedia(CheckIn.this, "bula.mp3");
        //---
        //CheckBalanceAndAutoSubmit();
    }

    private AdapterView.OnItemSelectedListener currentLocationItemClick = new AdapterView.OnItemSelectedListener()
    {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long rowId)
        {
            StagesOfRouteValue sel = (StagesOfRouteValue) parent.getItemAtPosition(position);

            Log.d(TAG, String.format("Select location: %d - %s", sel.StageISN, sel.StationName));
            currentLocation = sel;
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView)
        {
            currentLocation = null;
        }
    };

    private void RegisterPayByEvent()
    {
        Button btn = (Button) findViewById(R.id.check_in_v2_refund);
        btn.setOnClickListener(onRefundClick);
        //--
        Button cash_topup = (Button) findViewById(R.id.check_in_v2_cancel);
        cash_topup.setOnClickListener(onCancelClick);
    }

    private MediaPlayer errorVoice;

    private UIThreadHandler uiThreadHandler;

    @Override
    protected void onStart()
    {
        super.onStart();
        Log.d(TAG, "onStart...");

    }
/*
    private TimerTask autoSubmitTask = new TimerTask()
    {
        @Override
        public void run()
        {
            uiThreadHandler.sendEmptyMessage(UIThreadHandler.MSG_COUNT_DOWN);
        }
    };*/

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        super.onActivityResult(requestCode, resultCode, data);

        /*if (resultCode == RESULT_OK)
        {
            if (requestCode == Declarations.REQUEST_CASH_TOP_UP)
            {
                double cashTopUpAmount = data.getDoubleExtra("CASH_TOPUP_AMOUNT", 0);
                if (cashTopUpAmount > 0)
                {
                    //doPayCashAndTopUp(cashTopUpAmount);
                    DoCheckInAsync xTask = new DoCheckInAsync(
                            CheckInV2Cash.this,
                            progress,
                            DoCheckInAsync.CHECK_IN_BY_CASH_TOP_UP
                    );
                    xTask.execute(cashTopUpAmount);
                }
            }
            else if (requestCode == Declarations.REQUEST_STUDENT_VOUCHER)
            {
                double discountAmount = data.getDoubleExtra("VOUCHER_DISCOUNT_AMOUNT", 0);
                String voucherType = data.getStringExtra("VOUCHER_TYPE");
                int collectBalanceType = data.getIntExtra("VOUCHER_COLLECT_BALANCE_TYPE",
                        StudentVoucher.COMPLETE_PAYMENT_BY_VOUCHER);
                double collectAmount = data.getDoubleExtra("VOUCHER_COLLECT_CASH", 0);
                //--
                *//*doPayByStudentVoucher(
                        voucherType,
                        discountAmount,
                        collectBalanceType,
                        collectAmount);*//*
                DoCheckInAsync xTask = new DoCheckInAsync(
                        CheckInV2Cash.this,
                        progress,
                        DoCheckInAsync.CHECK_IN_BY_STUDENT_VOUCHER
                );
                xTask.execute(
                        voucherType,
                        discountAmount,
                        collectBalanceType,
                        collectAmount
                );
            }
            else if (requestCode == Declarations.REQUEST_REQUIRED_TOP_UP)
            {
                double topUpAmount = data.getDoubleExtra("TOP_UP_AMOUNT_RESULT", 0);
                if (topUpAmount > 0)
                {
                    if (AddTopUpTransaction(topUpAmount))
                    {
                        WorkingSession.getInstance().ShowToast(
                                CheckInV2Cash.this,
                                "Add Top Up transaction successful",
                                Toast.LENGTH_SHORT
                        );

                        //doTapIn();
                        DoCheckInAsync xTask = new DoCheckInAsync(
                                CheckInV2Cash.this,
                                progress,
                                DoCheckInAsync.CHECK_IN_BY_TAP_IN
                        );
                        xTask.execute();
                    }
                }
            }
        }*/
    }

    /*private boolean AddTopUpTransaction(double amount)
    {
        //--create top up transaction
        TransactionValue trans = WorkingSession.getInstance().CreateTransaction(
                CheckInV2Cash.this,
                "TOP-UP",
                "Cash",
                0,
                0, 0,
                amount,
                null, //voucher
                null, null,
                0,
                0, 0, 0, 0, 0, 0,
                null,
                ";;;;;");
        if (trans == null)
        {
            WorkingSession.getInstance().ShowErrorDialog(
                    CheckInV2Cash.this,
                    "Create Transaction Error",
                    "System Error.\nCould not create transaction, please contact your administrator."
            );

            return false;
        }
        try
        {
            long rx = db.addTransaction(trans);
            trans.ISN = (int) rx;
        }
        catch (Exception ex)
        {
            WorkingSession.getInstance().ShowErrorDialog(
                    CheckInV2Cash.this,
                    "Create Transaction Error",
                    "System Error.\nCould not create transaction, please contact your administrator."
            );

            return false;
        }
        //--update passenger balance
        WorkingSession.getInstance().currentPassenger.CurrentBalance += trans.TopUpAmount;
        int x = db.updateMemberBalance(
                WorkingSession.getInstance().currentPassenger.ISN,
                WorkingSession.getInstance().currentPassenger.CurrentBalance);

        return true;
    }*/

    private int InputValidate()
    {
        int inputValidateResult = 1;

        if (currentLocation == null)
        {
            WorkingSession.getInstance().ShowErrorDialog(
                    CheckInV2Cash.this,
                    "Error",
                    "Please select current location");

            inputValidateResult = 0;
        }
        else if (getPassengerCount() <= 0)
        {
            WorkingSession.getInstance().ShowErrorDialog(
                    CheckInV2Cash.this,
                    "Error",
                    "Please choose passenger type \n(Adult, Senior, Child, Disabled, Exempt or Student)"
            );

            inputValidateResult = 0;
        }

        return inputValidateResult;
    }

    private TransactionValue CreateTransaction(String type, double topUpAmount,
											   VoucherValue vv, boolean updateBalance)
    {
        TransactionValue trans = null;
        try
        {
            //---
            int adultCount = passengerCount[0];
            int seniorCount = passengerCount[2];
            int childCount = passengerCount[1];
            int disabledCount = passengerCount[3];
            //int exemptCount = NoOfPassenger(exempt);
            int studentCount = passengerCount[4];

            String description = String.format("Check-in near %s",
                    currentLocation.StationName);
            description += String.format(" for %d stages. ", stageCount);

            if (adultCount > 0)
                description += String.format("Adult: %d,", adultCount);
            if (seniorCount > 0)
                description += String.format(" Senior: %d,", seniorCount);
            if (childCount > 0)
                description += String.format(" Child: %d,", childCount);
            if (disabledCount > 0)
                description += String.format(" Disabled: %d,", disabledCount);
            /*if (exemptCount > 0)
                description += String.format(" Exempt: %d,", exemptCount);*/
            if (studentCount > 0)
                description += String.format(" Student: %d,", studentCount);

            description = description.substring(0, description.length() - 1);

            trans = WorkingSession.getInstance().CreateTransaction(
                    CheckInV2Cash.this,
                    "CHECK-IN",
                    type,
                    totalFare,
                    0, //freight
                    0,//ExcessiveBag
                    topUpAmount,
                    vv,
                    currentLocation,
                    null,
                    xStageFare,
                    adultCount,
                    seniorCount,
                    childCount,
                    disabledCount,
                    0,
                    studentCount,
                    null,
                    description
            );
            //--
            if (trans == null)
            {
                Message error = uiThreadHandler.CreateShowAlertDialogMsg(
                        "Create Transaction Error",
                        "System Error.\nCould not create transaction, please contact your administrator. [1]"
                );
                uiThreadHandler.sendMessage(error);

                /*WorkingSession.getInstance().ShowErrorDialog(
                        CheckIn.this,
                        "Create Transaction Error",
                        "System Error.\nCould not create transaction, please contact your administrator."
                );*/
                return null;
            }

            trans.CheckOutDate = new Date();

            try
            {
                long rx = db.addTransaction(trans);
                trans.ISN = (int) rx;
            }
            catch (Exception ex)
            {
                Message error = uiThreadHandler.CreateShowAlertDialogMsg(
                        "Create Transaction Error",
                        "System Error.\nCould not create transaction, please contact your administrator. [2]"
                );
                uiThreadHandler.sendMessage(error);

                return null;
            }

            if (trans.ISN == 0)
            {
                Message error = uiThreadHandler.CreateShowAlertDialogMsg(
                        "Create Transaction Error",
                        "System Error.\nCould not create transaction, please contact your administrator. [3]"
                );
                uiThreadHandler.sendMessage(error);

                return null;
            }
            //WorkingSession.getInstance().ShowToast(CheckIn.this, "Add transaction successful", Toast.LENGTH_SHORT);
            Message msg = uiThreadHandler.CreateShowToastMsg("Add transaction successful");
            uiThreadHandler.sendMessage(msg);
            //--
            if (updateBalance)
            {
                WorkingSession.getInstance().currentPassenger.CurrentBalance += trans.TopUpAmount - trans.FareAmount;
                int x = db.updateMemberBalance(
                        WorkingSession.getInstance().currentPassenger.ISN,
                        WorkingSession.getInstance().currentPassenger.CurrentBalance);
                if (x > 0)
                {
                    msg = uiThreadHandler.CreateShowToastMsg("Update customer balance successful");
                    uiThreadHandler.sendMessage(msg);
                    /*WorkingSession.getInstance().ShowToast(CheckIn.this,
                            "Update customer balance successful", Toast.LENGTH_SHORT);*/
                }
                else
                {
                    msg = uiThreadHandler.CreateShowToastMsg("Update customer balance failed");
                    uiThreadHandler.sendMessage(msg);
                    /*WorkingSession.getInstance().ShowToast(CheckIn.this,
                            "Update customer balance failed", Toast.LENGTH_SHORT);*/
                }
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }

        return trans;
    }

    private int getPassengerCount()
    {
        int x = 0;
        for(int i=0; i<passengerCount.length;i++)
            x+= passengerCount[i];
        return x;
    }

    private String CreateReceiptContent(TransactionValue xx)
    {
        Date date = new Date();
        String receiptDate = Utilities.DateToString(date, "dd/MM/yyyy");
        String receiptTime = Utilities.DateToString(date, "hh:mm a");

        String content = Utilities.StringAlignCenter(48, "BulaMy(Fiji) - BMF etikite  ") //+ "\n"
				+ Utilities.StringAlignCenter(48, "BMF Make It Your Choice")
				+ Utilities.StringAlignCenter(48, "www.bulamyfiji.com")
				+ "\n\n"
				+ Utilities.StringAlignLeftRight(48,
                    "Entry: " + currentLocation.StationName,
                    "Bus Reg.: " + WorkingSession.getInstance().journalBus.BusNumber
                ) + "\n"
                + Utilities.StringAlignLeftRight(48,
                    "Stages: " + stageCount,
                    "Driver: " + WorkingSession.getInstance().journalDriver.FullName
                ) + "\n"
                + Utilities.StringAlignLeftRight(48,
                    "No. PAX: " + String.valueOf(getPassengerCount()),
                    "Company: DeeCees Fiji Ltd"
                ) + "\n"
                + Utilities.StringAlignLeftRight(48,
                    "Fare: " +  WorkingSession.getInstance().decimalFormat.format(xStageFare),
                    "TIN: 12683467161"
                ) + "\n"
                + Utilities.StringAlignLeftRight(48,
                    "Total: " +  String.valueOf(WorkingSession.getInstance().RoundMoney(totalFare)),
                    "Issued: " + receiptDate
                ) + "\n"
                + Utilities.StringAlignLeftRight(48,
                    "ACCT Name: ",
                    receiptTime
                ) + "\n"
                + Utilities.StringAlignLeftRight(48,
                    "ACCT #: ",
                    "Mode: " + xx.Type
                ) + "\n"
                + Utilities.StringAlignLeftRight(48,
                    "Balance: ",
                    "Transaction ID: " +  xx.TransactionID
                ) + "\n"
                + "\nPlease Keep Receipt For Your Records\n\n";

        return content;
    }

    private boolean PrintReceipt(TransactionValue xx)
    {
		/*String x = db.getRuntimeValues("print-receipt");
		if(x == null || x.length() == 0)
			x = "1";
		if(x.equals("0"))
			return false;*/
		if(!WorkingSession.getInstance().printReceipt)
			return false;

        String receipt = CreateReceiptContent(xx);

        int rs = WorkingSession.getInstance().PreparePrintReceiptWifi(CheckInV2Cash.this, receipt, printReceiptCallback);

        if (rs == Declarations.NO_WIFI_PRINTER_SETUP)
        {
            Message error = uiThreadHandler.CreateShowToastMsg(
                    "No printer selected. Please setup one.");
            uiThreadHandler.sendMessage(error);
        }
        else if (rs == Declarations.PRINT_RECEIPT_ERROR)
        {
            Message error = uiThreadHandler.CreateShowToastMsg(
                    "Print receipt failed.");
            uiThreadHandler.sendMessage(error);
        }
        return rs == Declarations.PRINT_RECEIPT_WAITING;
    }

    private final Handler printReceiptCallback = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
			processing = false;
			//--
            Message error = null;
            switch (msg.what)
            {
				case Declarations.WIFI_PRINTER_CONNECTED:
					WorkingSession.getInstance().ShowToast(CheckInV2Cash.this,
							"Printer connected", Toast.LENGTH_SHORT);
					WorkingSession.getInstance().PrintReceipt();
					break;
                case Declarations.WIFI_PRINTER_CONNECTED_ERR:
                    Log.d(TAG, String.format(
                            "WIFI_PRINTER_CONNECTED_ERR. Unable connect to printer %s",
                            WorkingSession.getInstance().wifiPrinterAddress)
                    );
					try
					{
						progress.dismiss();
					}
					catch (Exception ex)
					{
						Log.e(TAG, "[CheckInV2Cash.onBackPress] " + ex.toString());
					}
					//--
					/*runOnUiThread(new Runnable()
					{
						@Override
						public void run()
						{
							SetAllButtonEnableState(true);
						}
					});*/

                    //--
                    AlertDialog.Builder dialog = new AlertDialog.Builder(CheckInV2Cash.this);
                    dialog.setNegativeButton("OK", new DialogInterface.OnClickListener()
                    {
                        @Override
                        public void onClick(DialogInterface dialog, int which)
                        {
                            uiThreadHandler.sendEmptyMessage(UIThreadHandler.DO_BACK_PRESS);
                        }
                    });
                    AlertDialog alert = dialog.create();
                    alert.setTitle("Print Receipt Error");
                    alert.setMessage(
                            String.format("Unable connect to printer %s",
                                    WorkingSession.getInstance().wifiPrinterAddress)
                    );
					alert.setCancelable(false);
                    //--
                    alert.show();
                    //--
                    break;
                case Declarations.WIFI_PRINTER_SEND_FAILED:
                    error = uiThreadHandler.CreateShowToastMsg(
                            "Unable send data to printer.");
                    uiThreadHandler.sendMessage(error);
                    break;
                case Declarations.PRINT_RECEIPT_SUCCESSFUL:
                    error = uiThreadHandler.CreateShowToastMsg(
                            "Print receipt successful.");
                    uiThreadHandler.sendMessage(error);

                    uiThreadHandler.sendEmptyMessage(UIThreadHandler.DO_BACK_PRESS);
                    break;
            }
        }
    };

    private void doPayByCash()
    {
        try
        {
			Log.e(TAG, "[doPayByCash] Set main INPUT_DIRECT_CHECK_IN = 1");
			Intent next = new Intent(CheckInV2Cash.this, Main.class);
			next.putExtra("INPUT_DIRECT_CHECK_IN", 1);
			if(Main.getInstance() != null)
				Main.getInstance().setIntent(next);
			//--
			Log.e(TAG, "[doPayByCash] Create transaction...");
            TransactionValue trans = CreateTransaction("Cash", 0, null, false);
			//-------------------TEST-------------------
			WorkingSession.getInstance().transactionCount++;
			//-------------------TEST-------------------
			Log.e(TAG, "[doPayByCash] Print receipt...");
            // print receipt
            if (!PrintReceipt(trans))
            {
                uiThreadHandler.sendEmptyMessage(UIThreadHandler.DO_BACK_PRESS);
                //onBackPressed();
            }
        }
        catch (Exception ex)
        {
            Log.e(TAG, "doPayByCash: " + ex.getMessage());
            Message error = uiThreadHandler.CreateShowAlertDialogMsg(
                    "System Error",
					"Ticket Error, Please Re-Enter Sale"
                    //ex.getMessage()
            );
            uiThreadHandler.sendMessage(error);

            /*WorkingSession.getInstance().ShowErrorDialog(
                    CheckIn.this,
                    "System Error",
                    ex.getMessage());*/
        }
		WorkingSession.getInstance().lastCashTransaction = new Date();
		//--
		//processing = false;
		Log.e(TAG, "[doPayByCash] Done");
    }

    //this function is called in onActivityResult
    private void doPayByStudentVoucher(
            String voucherType, double discountAmount,
            int collectBalanceType, double collectAmount)
    {
        try
        {
			Log.e(TAG, "[doPayByStudentVoucher] Set main INPUT_DIRECT_CHECK_IN = 1");
			Intent next = new Intent(CheckInV2Cash.this, Main.class);
			next.putExtra("INPUT_DIRECT_CHECK_IN", 1);
			if(Main.getInstance() != null)
				Main.getInstance().setIntent(next);
			//--
			Log.e(TAG, "[doPayByStudentVoucher] Create transaction...");
            VoucherValue vv = new VoucherValue();
            vv.VoucherType = voucherType;
            vv.VoucherAmount = discountAmount;

            TransactionValue trans = null;
            if (collectBalanceType == StudentVoucher.COMPLETE_PAYMENT_BY_VOUCHER)
            {
                trans = CreateTransaction(
                        "Student-Voucher",
                        0,
                        vv,
                        false);
            }
            /*else if (collectBalanceType == StudentVoucher.COMPLETE_PAYMENT_BY_BMF)
            {
                trans = CreateTransaction(
                        "BMF",
                        0,
                        vv,
                        false);
            }
            else if (collectBalanceType == StudentVoucher.COMPLETE_PAYMENT_BY_CASH)
            {
                trans = CreateTransaction(
                        "Cash",
                        collectAmount,
                        vv,
                        false);
            }*/
            if (trans == null)
            {
                WorkingSession.getInstance().ShowErrorDialog(
                        CheckInV2Cash.this,
                        "Error",
                        "System Error.\nCould not add Transaction"
                );
				processing = false;
                return;
            }
			//-------------------TEST-------------------
			WorkingSession.getInstance().transactionCount++;
			//-------------------TEST-------------------
			Log.e(TAG, "[doPayByStudentVoucher] Print receipt...");
            // print receipt
            if (!PrintReceipt(trans))
            {
                uiThreadHandler.sendEmptyMessage(UIThreadHandler.DO_BACK_PRESS);
                //onBackPressed();
            }
        }
        catch (Exception ex)
        {
            Log.e(TAG, "doPayByStudentVoucher: " + ex.getMessage());
            Message error = uiThreadHandler.CreateShowAlertDialogMsg(
                    "System Error",
					"Ticket Error, Please Re-Enter Sale"
                    //ex.getMessage()
            );
            uiThreadHandler.sendMessage(error);

            /*WorkingSession.getInstance().ShowToast(CheckIn.this, ex.getMessage(),
                    Toast.LENGTH_LONG);*/
        }
		WorkingSession.getInstance().lastCashTransaction = new Date();
		Log.e(TAG, "[doPayByStudentVoucher] Done");
    }

    OnClickListener onCancelClick = new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
			Log.d(TAG, "Canceling...");
			hardKeyBack = true;

            onBackPressed();
            /*Intent mainScreen = new Intent(CheckInV2Cash.this, Main.class);
            startActivity(mainScreen);*/
        }
    };

    private boolean processing = false;
    private boolean hardKeyBack = true;

    @Override
    public void onBackPressed()
    {
		//Log.e(TAG, "onBackPressed...");
        //--
		try
		{
        	progress.dismiss();
		}
		catch (Exception ex)
		{
			Log.e(TAG, "[CheckInV2Cash.onBackPress] " + ex.toString());
		}
		//--
		Intent next = new Intent(CheckInV2Cash.this, Main.class);
		if(hardKeyBack)
		{
			Log.d(TAG, "[CheckInV2Cash.onBackPress] Hard key");

			next.putExtra("INPUT_DIRECT_CHECK_IN", 0);
			if(Main.getInstance() != null)
				Main.getInstance().setIntent(next);
		}
		else
		{
			//--
			String cardNumber = db.getRuntimeValues("defaultCard");
			if (cardNumber == null || cardNumber.length() == 0)
			{
				Log.d(TAG, "[onBackPress] 1");
				next.putExtra("INPUT_DIRECT_CHECK_IN", 0);
				if(Main.getInstance() != null)
					Main.getInstance().setIntent(next);
			}
			else
			{
				Log.d(TAG, "[onBackPress] 2");
				//--
				next.putExtra("INPUT_DIRECT_CHECK_IN", 1);
				if(Main.getInstance() != null)
					Main.getInstance().setIntent(next);
			}
		}
		//super.onBackPressed();
		//--
		finish();
    }
//
//    @Override
//    public void onNewIntent(Intent intent)
//    {
//        String action = intent.getAction();
//        Log.d(TAG, String.format("[onNewIntent] Action: %s", action));
//
//        if (action != null &&
//				(action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)
//                || action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED))
//            && !processing)
//        {
//            String[] result = Utilities.readNFCTagContentAndSerial(CheckInV2Cash.this, intent);
//            //--result[0] = TagSerial, result[1] = Tag content
//            if (result == null || result.length < 2)
//                return;
//
//            if (result[1].length() == 0)
//            {
//				WorkingSession.getInstance().ShowErrorDialog(
//                        CheckInV2Cash.this,
//						"Error",
//                        "Invalid NFC Tag Content"
//                );
//				return;
//            }
//
//            MemberValue member = db.getMemberByCard(result[1], result[0]);
//
//            if (member != null)
//            {
//            	// go back to Home
//                Intent mainScreen = new Intent(CheckInV2Cash.this, Main.class);
//                mainScreen.putExtra("INPUT_CUSTOMER", member.CardNumber);
//                //startActivity(mainScreen);
//
//				if(Main.getInstance() != null)
//					Main.getInstance().setIntent(mainScreen);
//				finish();
//            }
//            else
//            {
//                //Utilities.PlayMedia(CheckIn.this, "C.mp3");
//                WorkingSession.getInstance().ShowErrorDialog(
//                        CheckInV2Cash.this,
//                        "Error",
//                        "Invalid Card Number: " + result[1]
//                );
//            }
//        }
//        else
//        {
//            Log.d(TAG, "Action: " + action + ", on processing current task");
//        }
//    }

    @Override
    protected void onResume()
    {
        Log.d(TAG, "[onResume] ....");
        super.onResume();
//        if (nfcAdapter != null)
//        {
//            nfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
//            // mAdapter.enableForegroundNdefPush(this);
//        }
    }

    @Override
    protected void onPause()
    {
        Log.d(TAG, "[onPause] ....");
        super.onPause();
//        if (nfcAdapter != null)
//        {
//            nfcAdapter.disableForegroundDispatch(this);
//            //nfcAdapter.disableForegroundNdefPush(this);
//            nfcAdapter.setNdefPushMessage(null, this);
//        }

        if(errorVoice != null)
            errorVoice.stop();
        //WorkingSession.getInstance().CancelShowingToast();
    }

    @Override
    protected void onDestroy()
    {
        Log.d(TAG, "[onDestroy] ....");
        super.onDestroy();
        /*if (autoSubmit != null)
            autoSubmit.cancel();*/
        if(errorVoice != null)
            errorVoice.stop();

    }

    private final class UIThreadHandler extends Handler
    {
        private final String TAG = "CheckInUIThreadHandler";
        public static final int MSG_COUNT_DOWN = 0x10;
        public static final int SHOW_TOAST = 0x11;
        public static final int SHOW_ALERT_DIALOG = 0x12;
        public static final int DO_CHECK_IN_BY_CASH = 0x13;
        public static final int DO_BACK_PRESS = 0x14;
        public static final int DO_TAP_IN = 0x15;
//        private int currentCountDownValue = Declarations.TAP_IN_TIMEOUT_SECONDS;

		//private Message currentMsg;


        public UIThreadHandler(Looper lp)
        {
            super(lp);
        }

        @Override
        public void handleMessage(Message msg)
        {
            try
            {
				//currentMsg = msg;
				//--
                switch (msg.what)
                {
                    case UIThreadHandler.SHOW_TOAST:
                    {
                        String content = msg.getData().getString("TOAST_CONTENT", "");
                        if(content.length() == 0)
                            break;
                        WorkingSession.getInstance().ShowToast(
                                CheckInV2Cash.this,
                                content,
                                Toast.LENGTH_SHORT);
                        break;
                    }
                    case UIThreadHandler.SHOW_ALERT_DIALOG:
                    {
						String title = msg.getData().getString("DIALOG_TITLE", "");
						String content = msg.getData().getString("DIALOG_CONTENT", "");
						if(content.length() == 0)
							break;
						WorkingSession.getInstance().ShowErrorDialog(
								CheckInV2Cash.this,
								title,
								content);

                        break;
                    }
                    case DO_CHECK_IN_BY_CASH:
                    {
                        //Thread.sleep(500);
                        Log.d(TAG, "Do Check-in by cash");
                        //--
                        DoCheckInAsync xTask = new DoCheckInAsync(
                                CheckInV2Cash.this,
                                progress,
                                DoCheckInAsync.CHECK_IN_BY_CASH
                        );
                        xTask.execute();
                        //--
                        break;
                    }
                    case DO_BACK_PRESS:
                        Thread.sleep(300);
						hardKeyBack = false;
						runOnUiThread(new Runnable()
						{
							@Override
							public void run()
							{
								onBackPressed();
							}
						});
                        //onBackPressed();
						break;
                }
            }
            catch (Exception ex)
            {
                Log.e(TAG, String.format("[MSG:%d] %s", msg.what, ex.getMessage()));
            }
        }

        public Message CreateShowToastMsg(String content)
        {
            Message msg = new Message();
            msg.what = SHOW_TOAST;

            Bundle data = new Bundle();
            data.putString("TOAST_CONTENT", content);
            msg.setData(data);

            return msg;
        }

        public Message CreateShowAlertDialogMsg(String dialogTitle, String content)
        {
            Message msg = new Message();
            msg.what = SHOW_ALERT_DIALOG;

            Bundle data = new Bundle();
            data.putString("DIALOG_TITLE", dialogTitle);
            data.putString("DIALOG_CONTENT", content);
            msg.setData(data);

            return msg;
        }
    }


    public class DoCheckInAsync extends AsyncTask<Object, Void, Void>
    {
        public static final int CHECK_IN_BY_BMF = 1000;
        public static final int CHECK_IN_BY_CASH = 1001;
        public static final int CHECK_IN_BY_CASH_TOP_UP = 1002;
        public static final int CHECK_IN_BY_STUDENT_VOUCHER = 1003;
        public static final int CHECK_IN_BY_TAP_IN = 1004;

        private ProgressDialog progress;
        private Context callerContext;
        private int checkInType;

        public DoCheckInAsync(Context context, ProgressDialog dialog, int checkInType)
        {
            callerContext = context;
            progress = dialog;
            this.checkInType = checkInType;
        }

        public void onPreExecute()
        {
			Log.i(TAG, "[DoCheckInAsync.onPreExecute] ...");
            processing = true;
			//--
			/*runOnUiThread(new Runnable()
			{
				@Override
				public void run()
				{
					SetAllButtonEnableState(false);
				}
			});*/
			try
			{
            	progress.show();
			}
			catch (Exception ex)
			{
				Log.e(TAG, "[DoCheckInAsync.onPreExecute] " + ex.toString());
			}
            //--
            super.onPreExecute();
        }

        public Void doInBackground(Object... inputValues)
        {
            try
            {
				Log.i(TAG, "[DoCheckInAsync.doInBackground] ...");
                switch (this.checkInType)
                {
                    case CHECK_IN_BY_CASH:
                        doPayByCash();
                        break;
                    case CHECK_IN_BY_STUDENT_VOUCHER:
                        doPayByStudentVoucher(
                                String.valueOf(inputValues[0]), //voucherType
                                ((Number)inputValues[1]).doubleValue(), //discountAmount
                                ((Number)inputValues[2]).intValue(), //collectBalanceType
                                ((Number)inputValues[3]).doubleValue() //collectAmount
                        );
                }
            }
            catch (Exception ex)
            {
                Log.e(TAG, "[DoCheckInAsync.doInBackground] " + ex.getMessage());
            }

            return null;
        }

        public void onPostExecute(Void unused)
        {
			Log.i(TAG, "[DoCheckInAsync.onPostExecute] ...");
            processing = false;
            super.onPostExecute(unused);
        }
    }

    private OnClickListener onAdultStageClick = new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
			if(processing)
				return;
			processing = true;
			try
			{
				Button button = (Button)v;
				Log.d(TAG, "[onAdultStageClick] " + button.getText());
				//--
				Arrays.fill(passengerCount, 0);
				passengerCount[0] = 1;
				stageCount =  Integer.parseInt(button.getText().toString());
				xStageFare = db.getStageFare(WorkingSession.getInstance().journalRoute.ISN, stageCount);
				totalFare = passengerCount[0] * xStageFare * (1 - GetPassengerTypeDiscount("adult"));
				//--
				if(!CompletePaymentByCash())
					processing = false;
			}
			catch (Exception ex)
			{
				WorkingSession.getInstance().ShowErrorDialog(
						CheckInV2Cash.this,
						"[Adult] Error",
						"System error, please contact your administrator.\n" + ex.getMessage());
				Log.e(TAG, "[onAdultStageClick] " + ex.toString());
				ex.printStackTrace();
				processing = false;
			}
        }
    };

    private OnClickListener onChildStageClick = new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
			if(processing)
				return;
			processing = true;
			//--
			try
			{
				Button button = (Button)v;
				Log.d(TAG, "[onChildStageClick] " + button.getText());
				//--
				Arrays.fill(passengerCount, 0);
				passengerCount[1] = 1;
				stageCount =  Integer.parseInt(button.getText().toString());
				xStageFare = db.getStageFare(WorkingSession.getInstance().journalRoute.ISN, stageCount);
				totalFare = passengerCount[1] * xStageFare * (1 - GetPassengerTypeDiscount("child"));
				//--
				if(!CompletePaymentByCash())
					processing = false;
			}
			catch (Exception ex)
			{
				WorkingSession.getInstance().ShowErrorDialog(
						CheckInV2Cash.this,
						"[Child] Error",
						"System error, please contact your administrator.\n" + ex.getMessage());
				Log.e(TAG, "[onChildStageClick] " + ex.toString());
				ex.printStackTrace();
				processing = false;
			}
        }
    };

    private OnClickListener onSeniorStageClick = new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
			if(processing)
				return;
			processing = true;
			//--
			try
			{
				Button button = (Button)v;
				Log.d(TAG, "[onSeniorStageClick] " + button.getText());
				//--
				Arrays.fill(passengerCount, 0);
				passengerCount[2] = 1;
				stageCount =  Integer.parseInt(button.getText().toString());
				xStageFare = db.getStageFare(WorkingSession.getInstance().journalRoute.ISN, stageCount);
				totalFare = passengerCount[2] * xStageFare * (1 - GetPassengerTypeDiscount("senior"));
				//--
				if(!CompletePaymentByCash())
					processing = false;
			}
			catch (Exception ex)
			{
				WorkingSession.getInstance().ShowErrorDialog(
						CheckInV2Cash.this,
						"[Senior] Error",
						"System error, please contact your administrator.\n" + ex.getMessage());
				Log.e(TAG, "[onSeniorStageClick] " + ex.toString());
				ex.printStackTrace();
				processing = false;
			}
        }
    };

    private OnClickListener onDisabledStageClick = new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
			if(processing)
				return;
			processing = true;
			//--
			try
			{
				Button button = (Button)v;
				Log.d(TAG, "[onDisabledStageClick] " + button.getText());
				//--
				Arrays.fill(passengerCount, 0);
				passengerCount[3] = 1;
				stageCount =  Integer.parseInt(button.getText().toString());
				xStageFare = db.getStageFare(WorkingSession.getInstance().journalRoute.ISN, stageCount);
				totalFare = passengerCount[3] * xStageFare * (1 - GetPassengerTypeDiscount("disabled"));
				//--
				if(!CompletePaymentByCash())
					processing = false;
			}
			catch (Exception ex)
			{
				WorkingSession.getInstance().ShowErrorDialog(
						CheckInV2Cash.this,
						"[Disabled] Error",
						"System error, please contact your administrator.\n" + ex.getMessage());
				Log.e(TAG, "[onDisabledStageClick] " + ex.toString());
				ex.printStackTrace();
				processing = false;
			}
        }
    };

    private void RegisterPassengerStageClickEvent()
    {
        for(int i=1; i<= stageCount && i <4; i++)
        {
            int id = -1;

            id = Utilities.getResId("stage_adult_" + i, CheckInV2Cash.this, R.id.class);
            if(id > -1)
			{
                ((Button) findViewById(id)).setOnClickListener(onAdultStageClick);
			}
            //--
            id = Utilities.getResId("stage_child_" + i, CheckInV2Cash.this, R.id.class);
            if(id > -1)
			{
                ((Button) findViewById(id)).setOnClickListener(onChildStageClick);
			}
            //--
            id = Utilities.getResId("stage_senior_" + i, CheckInV2Cash.this, R.id.class);
            if(id > -1)
			{
                ((Button) findViewById(id)).setOnClickListener(onSeniorStageClick);
			}
            //--
            id = Utilities.getResId("stage_disabled_" + i, CheckInV2Cash.this, R.id.class);
            if(id > -1)
			{
                ((Button) findViewById(id)).setOnClickListener(onDisabledStageClick);
			}
            //--
            id = Utilities.getResId("stage_student_" + i, CheckInV2Cash.this, R.id.class);
            if(id > -1)
            {
                Button btn = (Button)findViewById(id);
                btn.setTag(i);
                btn.setOnClickListener(onStudentClick);
            }
        }
    }

    private OnClickListener onRefundClick = new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            Intent input = new Intent(CheckInV2Cash.this, refund.class);
            input.putExtra("OPTION_NO_CARD", 1);
            startActivity(input);
        }
    };

    private boolean CompletePaymentByCash()
    {
		try
		{
			if(WorkingSession.getInstance().lastCashTransaction != null &&
					Utilities.DateDifferenceSecond(new Date(), WorkingSession.getInstance().lastCashTransaction) < 1.0)
			{
				Log.e(TAG, "You're submitting too fast. Please slow down");
				//WorkingSession.getInstance().lastCashTransaction = new Date();
				return false;
			}

			if (InputValidate() != 1) //not validate or waiting for confirm
				return false;

			//show total fare
			totalFareTextView.setText(String.valueOf(WorkingSession.getInstance().RoundMoney(totalFare)));
			//--
			DoCheckInAsync xTask = new DoCheckInAsync(
					CheckInV2Cash.this,
					progress,
					DoCheckInAsync.CHECK_IN_BY_CASH
			);
			xTask.execute();
		}
		catch (Exception ex)
		{
			WorkingSession.getInstance().ShowErrorDialog(
					CheckInV2Cash.this,
					"Error",
					"System error, please contact your administrator.\n" + ex.getMessage());
			return false;
		}
		return true;
    }

    private OnClickListener onStudentClick = new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
			if(processing)
				return;
			processing = true;
			//--
			try
			{
				Button btn = (Button)v;
				int x = Integer.parseInt(btn.getTag().toString());
				//--
				Log.d(TAG, "[onStudentClick] " + x);
				//--
				double discountAmount = (x == 3? 0.75d : (x == 2? 0.55d: 0.35d));
				String voucherType = (x == 3? "Red" : (x == 2? "Blue" : "Yellow"));
				int collectBalanceType = StudentVoucher.COMPLETE_PAYMENT_BY_VOUCHER;
				double collectAmount = 0;
				//--
				Arrays.fill(passengerCount, 0);
				passengerCount[4] = 1;
				stageCount =  x;
				xStageFare = db.getStageFare(WorkingSession.getInstance().journalRoute.ISN, stageCount);
				totalFare = passengerCount[4] * xStageFare * (1 - GetPassengerTypeDiscount("student"));
				//--
				if(!CompletePaymentByVoucher(
						voucherType,
						discountAmount,
						collectBalanceType,
						collectAmount))
				{
					processing = false;
				}
			}
			catch (Exception ex)
			{
				WorkingSession.getInstance().ShowErrorDialog(
						CheckInV2Cash.this,
						"[Student] Error",
						"System error, please contact your administrator.\n" + ex.getMessage());
				Log.e(TAG, "[onStudentClick] " + ex.toString());
				processing = false;
			}
        }
    };

    private boolean CompletePaymentByVoucher(
            String voucherType,
            double discountAmount,
            int collectBalanceType,
            double collectAmount
    )
    {
		if(WorkingSession.getInstance().lastCashTransaction != null &&
				Utilities.DateDifferenceSecond(new Date(), WorkingSession.getInstance().lastCashTransaction) < 1.0)
		{
			Log.e(TAG, "You're submitting too fast. Please slow down");
			//WorkingSession.getInstance().lastCashTransaction = new Date();
			return false;
		}
		//--
        if (InputValidate() != 1) //not validate or waiting for confirm
            return false;
        //show total fare
        totalFareTextView.setText(String.valueOf(WorkingSession.getInstance().RoundMoney(totalFare)));
        //--
        DoCheckInAsync xTask = new DoCheckInAsync(
                CheckInV2Cash.this,
                progress,
                DoCheckInAsync.CHECK_IN_BY_STUDENT_VOUCHER
        );
        xTask.execute(
                voucherType,
                discountAmount,
                collectBalanceType,
                collectAmount
        );

		return true;
    }

	private void SetAllButtonEnableState(boolean enable)
	{
		for(int i=1; i<= stageCount && i <4; i++)
		{
			int id = -1;

			id = Utilities.getResId("stage_adult_" + i, CheckInV2Cash.this, R.id.class);
			if(id > -1)
			{
				((Button) findViewById(id)).setEnabled(enable);
			}
			//--
			id = Utilities.getResId("stage_child_" + i, CheckInV2Cash.this, R.id.class);
			if(id > -1)
			{
				((Button) findViewById(id)).setEnabled(enable);
			}
			//--
			id = Utilities.getResId("stage_senior_" + i, CheckInV2Cash.this, R.id.class);
			if(id > -1)
			{
				((Button) findViewById(id)).setEnabled(enable);
			}
			//--
			id = Utilities.getResId("stage_disabled_" + i, CheckInV2Cash.this, R.id.class);
			if(id > -1)
			{
				((Button) findViewById(id)).setEnabled(enable);
			}
			//--
			id = Utilities.getResId("stage_student_" + i, CheckInV2Cash.this, R.id.class);
			if(id > -1)
			{
				Button btn = (Button)findViewById(id);
				((Button) findViewById(id)).setEnabled(enable);
			}
		}

		Button btn = (Button) findViewById(R.id.check_in_v2_refund);
		btn.setEnabled(enable);
		//--
		Button cash_topup = (Button) findViewById(R.id.check_in_v2_cancel);
		cash_topup.setEnabled(enable);
	}
}
